#include "stm32f10x.h"                  // Device header
#include "w25q16.h"
#include <stdlib.h>

//CS - PA2
//SCK - PA5
//MISO - PA6
//MOSI - PA7

void Spi_SW_W_CS(uint8_t BitVal)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_2, (BitAction)BitVal);
}

void Spi_SW_W_SCK(uint8_t BitVal)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitVal);
}

uint8_t Spi_SW_R_MISO(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}

void Spi_SW_W_MOSI(uint8_t data)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)data);
}

void Spi_SW_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	Spi_SW_W_CS(1);
	Spi_SW_W_SCK(0);
}

void Spi_SW_Start(void)
{
	Spi_SW_W_CS(0);
}

void Spi_SW_Stop(void)
{
	Spi_SW_W_CS(1);
}

uint8_t Spi_SW_SwapData(uint8_t SendData)
{
	uint8_t i;
	uint8_t RecieveData = 0x00;
	for (i = 0; i < 8; i ++)
	{
		Spi_SW_W_MOSI(SendData & (0x80 >> i));
		Spi_SW_W_SCK(1);
		if (Spi_SW_R_MISO() == 1){RecieveData |= (0x80 >> i);}
		Spi_SW_W_SCK(0);
	}
	return RecieveData;
}

void W25Q16_Init(void)
{
	Spi_SW_Init();
}

void W25Q16_GetID(uint8_t *MID, uint16_t *DID)
{
	Spi_SW_Start();
	
	Spi_SW_SwapData(W25Q16_INS_JEDEC_ID);
	*MID = Spi_SW_SwapData(W25Q16_INS_DUMMY);
	*DID = Spi_SW_SwapData(W25Q16_INS_DUMMY);
	*DID <<= 8;
	*DID |= Spi_SW_SwapData(W25Q16_INS_DUMMY);
	
	Spi_SW_Stop();
}

void W25Q16_WriteEnable(void)
{
	Spi_SW_Start();
	Spi_SW_SwapData(W25Q16_INS_WriteEnable);
	Spi_SW_Stop();
}

void W25Q16_WaitBusy(uint32_t timeout)
{
	Spi_SW_Start();
	Spi_SW_SwapData(W25Q16_INS_ReadStatusRegister1);
	while ((Spi_SW_SwapData(W25Q16_INS_DUMMY) & 0x01) == 1)
	{
		timeout--;
		if(timeout == 0)
		{
			//Wrong
			break;
		}
	}
	Spi_SW_Stop();	
}

void W25Q16_PageProgram(uint32_t Addr, uint8_t *DataArr, uint16_t Count)
{
	uint16_t i;
	
	W25Q16_WriteEnable();
	W25Q16_WaitBusy(10000);
	
	Spi_SW_Start();
	Spi_SW_SwapData(W25Q16_INS_PageProgram);	
	Spi_SW_SwapData(Addr >> 16);	//A23 - A16
	Spi_SW_SwapData(Addr >> 8);		//A15 - A8
	Spi_SW_SwapData(Addr);			//A7 - A0
	for(i = 0; i < Count; i++)
	{
		Spi_SW_SwapData(DataArr[i]);
	}
	Spi_SW_Stop();
}

void W25Q16_SectorErase(uint32_t Addr)
{
	W25Q16_WriteEnable();
	W25Q16_WaitBusy(10000);
	
	Spi_SW_Start();
	Spi_SW_SwapData(W25Q16_INS_SectorErase);
	Spi_SW_SwapData(Addr >> 16);	//A23 - A16
	Spi_SW_SwapData(Addr >> 8);		//A15 - A8
	Spi_SW_SwapData(Addr);			//A7 - A0	
	Spi_SW_Stop();
}

void W25Q16_ReadData(uint32_t Addr, uint8_t **DataArr, uint32_t Count)
{
	uint32_t i;
	
	W25Q16_WaitBusy(10000);
	
	Spi_SW_Start();
	Spi_SW_SwapData(W25Q16_INS_ReadData);	
	Spi_SW_SwapData(Addr >> 16);	//A23 - A16
	Spi_SW_SwapData(Addr >> 8);		//A15 - A8
	Spi_SW_SwapData(Addr);			//A7 - A0
	for(i = 0; i < Count; i++)
	{
		if(DataArr != NULL) if(*DataArr != NULL) (*DataArr)[i] = Spi_SW_SwapData(W25Q16_INS_DUMMY);
	}
	Spi_SW_Stop();
}
